﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bilibili.Model.Live;
using Bilibili.Model.Resource;
using Bilibili.Common;
using Bilibili.Common.Log;
using Bilibili.WebClient.Common;
using Newtonsoft.Json.Linq;
using PCLUntils.Objects;
using PCLUntils.Json;
using Bilibili.Common.Api;

namespace Bilibili.WebClient.Api
{
    public sealed class LiveRoomClient : ClientBase, IDisposable
    {
        private List<AllGiftsModel> AllGifts { get; set; }
        public async Task<ReturnModel<LiveInfoModel>> GetRoomInfo(int roomid)
        {
            try
            {
                ApiInfo apiInfo = new ApiInfo("https://api.live.bilibili.com/xlive/app-room/v1/index/getInfoByRoom", $"&actionkey=appkey&room_id={roomid}", true);
                var results = await ApiClient.GetResults(apiInfo);
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty())
                {
                    if (model.Code == 0)
                    {
                        var m = model.Json["data"].ToString().Replace("0000-00-00 00:00:00", "1990-01-01 00:00:00").ParseObject<LiveInfoModel>();
                        m.UserInfo = await GetUpInfo(m.room_info.uid);
                        return BuildSuccessResult(m);
                    }
                    else
                        return BuildFailedResult<LiveInfoModel>(model.Message);
                }
                else
                    return BuildFailedResult<LiveInfoModel>();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetRoomInfo", ex);
                return BuildExceptionResult<LiveInfoModel>(ex);
            }
        }
        public async Task<LiveUpModel> GetUpInfo(long userid)
        {
            try
            {
                ApiInfo apiInfo = new ApiInfo("https://api.live.bilibili.com/live_user/v1/card/card_up", $"&actionkey=appkey&uid={userid}", true);
                var results = await ApiClient.GetResults(apiInfo);
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty() && model.Code == 0)
                    return model.Json["data"].ToObject<LiveUpModel>();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetUpInfo", ex);
            }
            return null;
        }
        public async Task<ReturnModel<LivePlayUrlsModel>> GetRoomPlayurl(string roomid, int quality)
        {
            try
            {
                var results = await ApiClient.GetResults($"https://api.live.bilibili.com/xlive/web-room/v1/playUrl/playUrl?cid={roomid}&qn={quality}&platform=web");
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty())
                {
                    if (model.Code == 0)
                    {
                        var m = model.Json["data"].ToObject<LivePlayUrlsModel>();
                        int index = 1;
                        foreach (var item in m.durl)
                        {
                            item.display = "线路" + index;
                            index++;
                        }
                        return BuildSuccessResult(m);
                    }
                    else
                        return BuildFailedResult<LivePlayUrlsModel>(model.Message);
                }
                else
                    return BuildFailedResult<LivePlayUrlsModel>();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetRoomPlayurl", ex);
                return BuildExceptionResult<LivePlayUrlsModel>(ex);
            }
        }
        public async Task<ReturnModel<RoundModel>> GetRoundPlayurl(string roomid)
        {
            try
            {
                ApiInfo apiInfo = new ApiInfo("https://api.live.bilibili.com/live/getRoundPlayVideo", $"room_id={roomid}&type=flv", false);
                var url = GetSignUrl(apiInfo.ToString());
                var results = await ApiClient.GetResults(url);
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty())
                {
                    if (model.Code == 0)
                    {
                        var m = model.Json["data"].ToObject<RoundModel>();
                        var results2 = await ApiClient.GetResults(m.play_url);
                        var play = results2.ParseObject<RoundPlayModel>();
                        m.data = play;
                        if (play.durl.Count != 0)
                            return BuildSuccessResult(m);
                        else
                            return BuildFailedResult<RoundModel>("读取轮播地址失败");
                    }
                    else
                        return BuildFailedResult<RoundModel>(model.Message);
                }
                else
                    return BuildFailedResult<RoundModel>();
            }
            catch (Exception ex)
            {
                return BuildExceptionResult<RoundModel>(ex);
            }
        }
        public async Task<ReturnModel> SendDanmu(string text, string roomId)
        {
            try
            {
                var apiInfo = new ApiInfo("https://api.live.bilibili.com/api/sendmsg", "&actionKey=appkey", true);
                string sendText = $"cid={roomId}&mid={ApiProvider.Instance.CurrentUserId}&msg={text}&rnd={ApiProvider.Instance.TimeSpanSeconds}&mode=1&pool=0&type=json&color=16777215&fontsize=25&playTime=0.0";
                string result = await ApiClient.PostResults(apiInfo, sendText);
                var jb = result.ToJObject();
                if (jb.IsNotEmpty())
                {
                    if (jb["code"].ToInt32() == 0)
                        return BuildSuccessResult();
                    else
                        return BuildFailedResult("发送弹幕失败" + jb["msg"]);
                }
                else
                    return BuildFailedResult();
            }
            catch (Exception ex)
            {
                return BuildExceptionResult(ex);
            }
        }
        public async Task<ReturnModel<List<LiveMyGiftsModel>>> GetMyGifts()
        {
            try
            {
                if (!ApiProvider.Instance.IsLogin)
                    return BuildFailedResult<List<LiveMyGiftsModel>>("请先登录");
                if (AllGifts == null)
                {
                    var all = await GetAllGifts();
                    if (!all.Success)
                        return BuildFailedResult<List<LiveMyGiftsModel>>("加载我的包裹失败");
                    AllGifts = all.Data;
                }
                var apiInfo = new ApiInfo("https://api.live.bilibili.com/gift/v2/gift/bag_list", "&actionKey=appkey", true);
                var results = await ApiClient.GetResults(apiInfo);
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty())
                {
                    if (model.Code == 0)
                    {
                        var ls = model.Json["data"]["list"].ToObject<List<LiveMyGiftsModel>>();
                        foreach (var item in ls)
                            item.img = AllGifts.FirstOrDefault(x => x.id == item.gift_id).img_basic;
                        return BuildSuccessResult(ls);
                    }
                    else
                        return BuildFailedResult<List<LiveMyGiftsModel>>(model.Message);
                }
                else
                    return BuildFailedResult<List<LiveMyGiftsModel>>();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetMyGifts", ex);
                return BuildExceptionResult<List<LiveMyGiftsModel>>(ex);
            }
        }
        public async Task<ReturnModel> SendGift(long uid, string ruid, int gift_id, int gift_num, string roomid, string coin_type, int price)
        {
            try
            {
                var dataInfo = new DataInfo($"actionKey=appkey&biz_code=live&biz_id={roomid}&coin_type={coin_type}&gift_id={gift_id}&gift_num={gift_num}&price={price}&rnd={ApiProvider.Instance.TimeSpanSeconds}&ruid={ruid}&uid={uid}"
                    , ApiProviderBase.Build5);
                var results = await ApiClient.PostResultsUtf8("https://api.live.bilibili.com/gift/v2/live/send", dataInfo.ToString());
                var json = results.ToDynamicJObject();
                if (json.IsNotEmpty())
                {
                    if (json.Code == 0)
                        return BuildSuccessResult();
                    else
                        return BuildFailedResult(json.Message);
                }
                else
                    return BuildFailedResult();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("SendGift", ex);
                return BuildExceptionResult(ex);
            }
        }
        public async Task<ReturnModel> SendMyGift(long uid, string ruid, int gift_id, int gift_num, int bag_id, string roomid)
        {
            try
            {
                var apiInfo = new ApiInfo("https://api.live.bilibili.com/gift/v2/live/bag_send", "&actionKey=appkey", true);
                string data = $"uid={uid}&ruid={ruid}&gift_id={gift_id}&gift_num={gift_num}&bag_id={bag_id}&biz_id={roomid}&rnd={ApiProvider.Instance.TimeSpanSeconds}&biz_code=live";
                var results = await ApiClient.PostResultsUtf8(apiInfo, data);
                var json = results.ToDynamicJObject();
                if (json.IsNotEmpty())
                {
                    if (json.Code == 0)
                        return BuildSuccessResult();
                    else
                        return BuildFailedResult(json.Message);
                }
                else
                    return BuildFailedResult();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("SendMyGift", ex);
                return BuildExceptionResult(ex);
            }
        }
        public async Task<ReturnModel<List<GuardRankListModel>>> GetGuardRank(long uid, string roomId)
        {
            try
            {
                var apiInfo = new ApiInfo("https://api.live.bilibili.com/xlive/app-room/v2/guardTab/topList", $"&roomid={roomId}&page=1&page_size=30&ruid={uid}", true);
                var results = await ApiClient.GetResults(apiInfo);
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty())
                {
                    if (model.Code == 0)
                    {
                        var guards = model.Json["data"]["top3"].ToObject<List<GuardRankListModel>>();
                        var ls = model.Json["data"]["list"].ToObject<List<GuardRankListModel>>();
                        if (ls != null)
                            guards.AddRange(ls);
                        return BuildSuccessResult(guards);
                    }
                    else
                        return BuildFailedResult<List<GuardRankListModel>>(model.Message);
                }
                else
                    return BuildFailedResult<List<GuardRankListModel>>();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetGuardRank", ex);
                return BuildExceptionResult<List<GuardRankListModel>>(ex);
            }
        }
        public async Task<ReturnModel<List<LiveRoomRankItemModel>>> RoomRankList(long ruid, int roomid, string rank_type, int next_offset = 0)
        {
            try
            {
                var apiInfo = new ApiInfo("https://api.live.bilibili.com/rankdb/v1/RoomRank/tabRanks",
                    $"&next_offset={next_offset}&room_id={roomid}&ruid={ruid}&rank_type={rank_type}", false);
                var results = await ApiClient.GetResults(apiInfo);
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty())
                {
                    if (model.Code == 0)
                    {
                        var ls = model.Json["data"]["list"].ToObject<List<LiveRoomRankItemModel>>();
                        return BuildSuccessResult(ls);
                    }
                }
                return BuildFailedResult<List<LiveRoomRankItemModel>>();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetRankActivity", ex);
                return BuildExceptionResult<List<LiveRoomRankItemModel>>(ex);
            }
        }
        public async Task<ReturnModel<List<GiftTopListModel>>> GetGiftTop(int roomid)
        {
            try
            {
                var apiInfo = new ApiInfo("https://api.live.bilibili.com/AppRoom/getGiftTop", $"actionKey=appkey&room_id={roomid}", false);
                var results = await ApiClient.GetResults(apiInfo);
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty())
                {
                    if (model.Code == 0)
                    {
                        var ls = model.Json["data"]["list"].ToObject<List<GiftTopListModel>>();
                        return BuildSuccessResult(ls);
                    }
                    else
                        return BuildFailedResult<List<GiftTopListModel>>(model.Message);
                }
                else
                    return BuildFailedResult<List<GiftTopListModel>>();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetGiftTop", ex);
                return BuildExceptionResult<List<GiftTopListModel>>(ex);
            }
        }
        public async Task<ReturnModel<List<MedalRankListModel>>> GetMedalRankList(int roomid)
        {
            try
            {
                var apiInfo = new ApiInfo("https://api.live.bilibili.com/AppRoom/medalRankList", $"actionKey=appkey&room_id={roomid}", false);
                var results = await ApiClient.GetResults(apiInfo);
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty())
                {
                    if (model.Code == 0)
                    {
                        var ls = model.Json["data"]["list"].ToObject<List<MedalRankListModel>>();
                        var index = 1;
                        foreach (var item in ls)
                        {
                            item.rank = index;
                            index++;
                        }
                        return BuildSuccessResult(ls);
                    }
                    else
                        return BuildFailedResult<List<MedalRankListModel>>(model.Message);
                }
                else
                    return BuildFailedResult<List<MedalRankListModel>>();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetMedalRankList", ex);
                return BuildExceptionResult<List<MedalRankListModel>>(ex);
            }
        }
        public async Task<ReturnModel<List<AllGiftsModel>>> GetRoomGifts(int roomid, int area_v2_id, int area_v2_parent_id)
        {
            try
            {
                if (AllGifts == null)
                {
                    var all = await GetAllGifts();
                    if (!all.Success)
                        return BuildFailedResult<List<AllGiftsModel>>("无法读取礼物");
                    AllGifts = all.Data;
                }
                var roomGifts = new List<AllGiftsModel>();
                var apiInfo = new ApiInfo("https://api.live.bilibili.com/gift/v3/live/room_gift_list", $"actionkey=appkey&area_v2_id={area_v2_id}&area_v2_parent_id={area_v2_parent_id}&roomid={roomid}", true);
                var results = await ApiClient.GetResults(apiInfo);
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty())
                {
                    if (model.Code == 0)
                    {
                        foreach (var item in model.Json["data"]["list"])
                        {
                            var id = item["id"].ToInt32();
                            roomGifts.Add(AllGifts.FirstOrDefault(x => x.id == id));
                        }
                        roomGifts.Add(AllGifts.FirstOrDefault(x => x.id == 1));
                        return BuildSuccessResult(roomGifts);
                    }
                    else
                        return BuildFailedResult<List<AllGiftsModel>>(model.Message);
                }
                else
                    return BuildFailedResult<List<AllGiftsModel>>();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetRoomGifts", ex);
                return BuildExceptionResult<List<AllGiftsModel>>(ex);
            }
        }
        public async Task<ReturnModel<List<AllGiftsModel>>> GetAllGifts()
        {
            try
            {
                var apiInfo = new ApiInfo("https://api.live.bilibili.com/gift/v3/live/gift_config", "actionKey=appkey", false);
                var results = await ApiClient.GetResults(apiInfo);
                var model = results.ToDynamicJObject();
                if (model.IsNotEmpty())
                {
                    if (model.Code == 0)
                    {
                        var m = model.Json["data"].ToObject<List<AllGiftsModel>>();
                        return BuildSuccessResult(m);
                    }
                    else
                        return BuildFailedResult<List<AllGiftsModel>>(model.Message);
                }
                else
                    return BuildFailedResult<List<AllGiftsModel>>();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetAllGifts", ex);
                return BuildExceptionResult<List<AllGiftsModel>>(ex);
            }
        }
        public async Task<ReturnModel<JObject>> RoomEntryAction(string roomId)
        {
            try
            {
                var apiInfo = new ApiInfo("https://api.live.bilibili.com/room/v1/Room/room_entry_action", $"&actionKey=appkey&room_id={roomId}", true);
                var results = await ApiClient.GetResults(apiInfo);
                var obj = results.ToJObject();
                return BuildSuccessResult(obj);
            }
            catch (Exception ex)
            {
                return BuildExceptionResult<JObject>(ex);
            }
        }
        public void Dispose()
        {
            try
            {
                AllGifts?.Clear();
            }
            catch { }
        }
    }
}